package com.mrd.base;

import com.mrd.exception.DeleteException;
import com.mrd.exception.QueryException;
import com.mrd.exception.SaveException;
import com.mrd.framework.ui.Jqgrid;
import com.mrd.framework.ui.filter.Filter;
import com.mrd.framework.ui.filter.FilterGroupOption;
import com.mrd.framework.ui.filter.SearchRule;
import com.mrd.framework.ui.filter.SearchRuleOption;
import com.mrd.spring.repository.BaseRepository;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Sort;
import org.springframework.transaction.annotation.Transactional;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.persistence.Id;

/**
 * <p>
 * application name: sample
 * <p>
 * copyright: Copyright@2012 明睿达科技有限公司
 */

/**
 * @author qiul
 */
public abstract class BaseBiz<T> {

  protected BaseRepository<T, String> baseRepository;

  public Page<T> findByJqgrid(Jqgrid jqgrid) throws QueryException {
    return getBaseRepository().findByJqgrid(jqgrid);
  }

  /**
   * 通过查询图和jqgrid对象查询数据
   *
   * @param jqgrid jqgrid对象
   * @param graphName 查询图的名称
   * @return 查询的结果
   */
  public Page<T> findByJqgrid(Jqgrid jqgrid, String graphName) throws QueryException {
    return getBaseRepository().findByJqgrid(jqgrid, graphName);
  }

  /**
   * 通过分页查询获取记录,不加入其他参数，当startIndex大于0时分页才会生效
   *
   * @param startIndex 开始序号
   * @param size 获取记录数量
   */
  public List<T> findEntityByPage(int startIndex, int size) throws QueryException {
    return getBaseRepository().findEntityByPage(startIndex, size);
  }

  /**
   * 通过分页查询排序后的记录，当startIndex大于0时分页才会生效
   * 
   * @param startIndex 开始序号
   * @param size 获取记录数
   * @param order 排序字段
   * @return
   * @throws QueryException
   */
  // public List<T> findEntityByPage(int startIndex,int size,Order order) throws QueryException {
  // return getBaseRepository().findEntityByPage(startIndex, size, order);
  // }

  /**
   * 查找所有的记录
   */
  public List<T> findAllEntity() throws QueryException {
    return getBaseRepository().findAllEntity();
  }

  /**
   * 返回总计记录数
   */
  public int findEntityCount() throws QueryException {
    return getBaseRepository().findEntityCount();
  }

  /*
   * (non-Javadoc)
   * 
   * @see com.mrd.base.biz.BaseBiz#findEntityById(java.lang.String)
   */

  public T findEntityById(String id) throws QueryException {
    return getBaseRepository().findEntityById(id);
  }


  public T findEntityByBpk(String bpk) throws QueryException {
    if (StringUtils.isEmpty(bpk)) {
      return null;
    }
    Filter filter = new Filter();
    filter.setGroupOp(FilterGroupOption.AND);
    filter.addRule(new SearchRule("bpk", SearchRuleOption.cn, bpk));
    int count = getBaseRepository().findEntityCount(filter);
    if (count == 1) {
      return getBaseRepository().findEntityByFilter(0, 1, filter, null).get(0);
    }
    return null;
  }

  @Transactional
  public void saveOrupdateEntity(T entity) throws SaveException {
    getBaseRepository().saveOrupdate(entity);
  }

  @Transactional
  public void updateByHql(String hql) throws SaveException {
    getBaseRepository().updateByHql(hql);
  }

  @Transactional
  public void updateBySql(String sql) throws Exception {
    getBaseRepository().updateBySql(sql);
  }

  @Transactional
  public void excuteSql(String sql, Map<String, Object> parameters) throws Exception {
    getBaseRepository().excuteSql(sql, parameters);
  }

  @Transactional
  public void updateEntity(T entity, List<String> properties) throws SaveException {
    try {
      if (properties == null || properties.size() == 0) {
        saveOrupdateEntity(entity);
      } else {
        String id = getIdValue(entity);
        if (StringUtils.isEmpty(id)) {
          return;
        }
        // 根据id查出原始数据
        T entityTmp = findEntityById(id);
        PropertyDescriptor[] pds = BeanUtils.getPropertyDescriptors(entity.getClass());
        // 忽略的字段
        List<String> ignoreProperties = new ArrayList<String>();
        for (PropertyDescriptor pd : pds) {
          if (!properties.contains(pd.getName())) {
            ignoreProperties.add(pd.getName());
          }
        }
        // 将需要更新的内容拷贝进入查出来的数据中
        BeanUtils.copyProperties(entity, entityTmp, ignoreProperties.toArray(new String[0]));
        // 保存数据
        saveOrupdateEntity(entityTmp);
        entity = entityTmp;
      }
    } catch (Exception e) {
      e.printStackTrace();
      throw new SaveException(e);
    }
  }

  /**
   * 通过jqgrid过滤对象过滤查询结果，当startIndex大于0时分页才会生效
   *
   * @param startIndex 分页起始值
   * @param size 分页大小
   * @param filter 过滤对象
   * @param order 排序对象
   */
  public List<T> findEntityByFilter(int startIndex, int size, Filter filter, Sort.Order order)
      throws QueryException {
    return getBaseRepository().findEntityByFilter(startIndex, size, filter, order);
  }

  /**
   * 更加jqgrid过滤对象来查询记录数
   *
   * @param filter 过滤对象
   */
  public int findEntityCount(Filter filter) throws QueryException {
    return getBaseRepository().findEntityCount(filter);
  }

  /**
   * 删除对象
   *
   * @param entity 对象
   * @throws DeleteException 删除过程中发生错误则抛出此异常
   */
  @Transactional
  public void delete(T entity) throws DeleteException {
    getBaseRepository().delete(entity);
  }

  /**
   * 根据hql查询分页记录,传入参数，当startIndex大于0时分页生效
   */

  public List<T> findEntityByHql(String hql, int startIndex, int size, Filter filters) {
    // TODO: 2016/8/13
    // return getBaseRepository().findEntityByHql(hql, startIndex, size, filters);
    try {
      return (List<T>) getBaseRepository().findEntityByHql(hql, startIndex, size, null);
    } catch (QueryException e) {
      e.printStackTrace();
    }
    return null;
  }

  /*
   * (non-Javadoc)
   * 
   * @see com.mrd.base.biz.BaseSerBiz#oprateData(com.mrd.util.search.Filter)
   */
  @Transactional
  public int deleteByFilter(Filter filter) throws DeleteException {
    return getBaseRepository().deleteByFilter(filter);
  }

  /*
   * (non-Javadoc)
   * 
   * @see com.mrd.base.biz.BaseSerBiz#delete(java.lang.Object, boolean)
   */
  @Transactional
  public void delete(T entity, boolean findBeforDelete) throws DeleteException {
    getBaseRepository().delete(entity, findBeforDelete);
  }


  public List<Object> findObjectByHql(String hql, int page, int size,
      Map<String, Object> parameters) throws QueryException {
    return getBaseRepository().findEntityByHql(hql, page, size, parameters);
  }

  @SuppressWarnings("rawtypes")
  private String getIdValue(T entity) {
    String idValue = null;
    Class bc = entity.getClass();
    while (bc != null) {
      Field[] fields = bc.getDeclaredFields();
      for (Field field : fields) {
        Id id = field.getAnnotation(Id.class);
        if (id != null) {
          if (!field.isAccessible()) {
            field.setAccessible(true);
          }
          try {
            idValue = field.get(entity).toString();
          } catch (IllegalArgumentException e) {
            e.printStackTrace();
          } catch (IllegalAccessException e) {
            e.printStackTrace();
          }
          break;
        }
      }
      bc = bc.getSuperclass();
    }
    return idValue;
  }


  public List<Object> findObjectBySql(String sql, int startIndex, int size,
      Map<String, Object> parameters) throws QueryException {
    return getBaseRepository().findEntityBySql(sql, startIndex, size, parameters);
  }


  public int findEntityCountByHql(String hql, Map<String, Object> parameters)
      throws QueryException {
    return getBaseRepository().findEntityCountByHql(hql, parameters);
  }


  public int findEntityCountBySql(String sql, Map<String, Object> parameters)
      throws QueryException {
    return getBaseRepository().findEntityCountBySql(sql, parameters);
  }

  public abstract void setBaseRepository(BaseRepository<T, String> baseRepository);

  public BaseRepository<T, String> getBaseRepository() {
    return baseRepository;
  }

  /**
   * 根据主键删除对象
   *
   * @param id 主键值
   */
  @Transactional
  public void delete(String id) {
    if (StringUtils.isEmpty(id)) {
      return;
    }
    getBaseRepository().delete(id);
  }

  /**
   * 批量删除对象
   *
   * @param entities 多个对象的集合
   */
  @Transactional
  public void delete(Iterable<T> entities) {
    if (entities == null) {
      return;
    }
    getBaseRepository().delete(entities);
  }

}
